// 出处： https://www.bilibili.com/read/cv22740260/?from=search&spm_id_from=333.337.0.0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hs/hs.h>

#define BUF_SIZE 65536

// 回调函数
static int on_match(unsigned int id, unsigned long long from,
    unsigned long long to, unsigned int flags, void *ctx)
{
    printf("Match found at end position %llu, pattern ID %u\n", to, id);
    return 0;
}

int main(int argc, char **argv)
{
    // 正则表达式、编号、编译标志数组
    const char *patterns[] = {"ab+", "cd{2,}", "ef{1,3}"};
    const unsigned int ids[] = {1, 2, 3};
    const unsigned int flags[] = {HS_FLAG_CASELESS,
                                  HS_FLAG_CASELESS,
                                  HS_FLAG_CASELESS};

    unsigned int num_patterns = sizeof(patterns) / sizeof(const char *);

    // 编译正则表达式
    hs_database_t *database = NULL;
    hs_error_t err;
    hs_compile_error_t *compile_err = NULL;

    // 注意需要指定HS_MODE_STREAM模式
    err = hs_compile_multi(patterns, flags, ids, num_patterns, HS_MODE_STREAM,
            NULL, &database, &compile_err);
    if (err != HS_SUCCESS) {
        fprintf(stderr, "Error compiling pattern: %s\n", compile_err->message);
        hs_free_compile_error(compile_err);
        return -1;
    }

    // 分配临时空间(指针必须初始化为NULL)
    hs_scratch_t *scratch = NULL;
    err = hs_alloc_scratch(database, &scratch);
    if (err != HS_SUCCESS) {
        fprintf(stderr, "Error allocating scratch space\n");
        hs_free_database(database);
        return 1;
    }

    // 创建流匹配指针
    hs_stream_t *stream = NULL;
    err = hs_open_stream(database, 0, &stream);
    if (err != HS_SUCCESS) {
        fprintf(stderr, "Error creating stream: %d\n", err);
        hs_free_database(database);
        return -1;
    }

    // 读入数据
    char buf[BUF_SIZE];
    size_t len;
    FILE *fp = fopen("input.txt", "r");
    if (fp == NULL) {
        perror("Error opening input file");
        hs_close_stream(stream, scratch, NULL, NULL);
        hs_free_database(database);
        hs_free_scratch(scratch);
        return -1;
    }

    // 多模+流匹配
    while ((len = fread(buf, 1, BUF_SIZE, fp)) > 0) {
        err = hs_scan_stream(stream, buf, len, 0, scratch, on_match, NULL);
        if (err != HS_SUCCESS) {
            fprintf(stderr, "Error scanning stream: %d\n", err);
            break;
        }
    }
    if (ferror(fp)) {
        perror("Error reading input file");
    }

    // 关闭流
    hs_close_stream(stream, scratch, NULL, NULL);
    // 释放空间
    hs_free_scratch(scratch);
    hs_free_database(database);
    // 关闭文件
    fclose(fp);

    return 0;
}
